/**
 * Created by xinxinran on 2017/1/1.
 */
'use strict';
const targetCache = {},
    apiParamName = 'apiVer',
    beanUtil = require('../utils/beanUtil'),
    responseUtil = require('../utils/responseUtil'),
    loggerUtil = require('../utils/loggerUtil'),
    Promise = require('bluebird'),
    co = require('co');

function getBeanName(serviceName, apiVer){
    return serviceName.charAt(0).toUpperCase() + serviceName.substring(1) + 'Service' + (apiVer ? '_' + apiVer : '');
}

function isGenerator(obj) {
    return 'function' === typeof obj.next && 'function' === typeof obj.throw;
}

function isGeneratorFunction(obj) {
    let constructor = obj.constructor;
    if (!constructor) {
        return false;
    }
    if ('GeneratorFunction' === constructor.name || 'GeneratorFunction' === constructor.displayName){
        return true;
    }
    return isGenerator(constructor.prototype);
}

const doService = function(serviceName, funcName, req, res, next){
    const apiVer = req.params[apiParamName],        //TODO 应该查最新
        targetService = beanUtil.getBean(getBeanName(serviceName, apiVer)),
        target = targetService && targetService[funcName],
        logger = loggerUtil.getLogger(), startTs = new Date();

    //noinspection JSUnresolvedFunction
    Promise.try(() => {
        let funcParam, reqContentType, targetFunc = targetService[funcName];
        //noinspection JSUnresolvedFunction
        res.charSet && res.charSet('utf-8');

        switch(reqContentType = req.contentType()){
            case 'application/json':
                funcParam = {jsonBody : req.body, params : req.params};
                break;
            case 'application/x-www-form-urlencoded':
                funcParam = {jsonBody : null, params : req.params};
                break;
            case 'multipart/form-data':
                funcParam = {params : req.body, files : req.files};
                break;
            case 'socket/json' :
                let fileBuffer;
                if(req.body instanceof Buffer){
                    fileBuffer = req.body;
                }
                funcParam = {params : req.params, fileBuffer};
                break;
            default:
                logger.warn(`Unsupported Content-Type : ${reqContentType}`);
                funcParam = {jsonBody : null, params : req.params};
                break;
        }
        if(target){
            if(isGeneratorFunction(targetFunc)){
                return co(targetFunc.call(targetService, funcParam || {}));
            }else{
                return targetFunc.call(targetService, funcParam || {});
            }
        }else{
            //noinspection ExceptionCaughtLocallyJS
            throw  '未找到接口入口:' + serviceName + '->' + funcName + ':' + apiVer;
        }
    }).then(result => {
        return targetService.preProcessResult(result);
    }).then(result => {
        res.send(result);
        next();
    }).catch(err => {
        logger.error(err);
        if(targetService){
            res.send(responseUtil.makeErrorResponse(err, targetService.getRespTpl()));
        }else{
            res.send({code: -1, msg : "[FATAL] targetService not found : " + serviceName});
        }
        next();
    }).finally(() => {
        logger.debug(`Service Execution -> ${serviceName}.${funcName}, during time : ${new Date - startTs}ms`);
    });

};

exports.handleService = function(todoName){
    const todoSplit = todoName.split('.'),
        serviceName = todoSplit[0],
        funcName = todoSplit[1];
    let targetService = targetCache[todoName];
    if(!targetService){
        targetService = doService.bind(null, serviceName, funcName);
        targetCache[todoName] = targetService;
    }
    return targetService;
};